#ifndef _OCCI_DRIVER_H_
#define _OCCI_DRIVER_H_

#include <buildspec.h>
#include <Client/ClientUtils/Network/RDBDriverInterface.h>
#include <Client/ClientUtils/Network/NetworkInterface.h>

#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>

#include <Client/ClientUtils/Network/occi/occi_include.h>

namespace GST {
namespace ClientUtils {

	class OCCIDriver;
	typedef boost::shared_ptr<OCCIDriver> OCCIDriverPtr;

	/** OCCIECHandle: short for OCCIEnvironmentConnectionHandle */
	struct GST_API_EXPORT OCCIECHandle
	{
		oc::Connection * m_connection;
		oc::Environment * m_environment;
		OCCIECHandle();
		~OCCIECHandle();

		void setConnection(oc::Connection * con);
		bool is_closed() const;
	};
	typedef boost::shared_ptr<OCCIECHandle> OCCIEnvPtr;

	struct GST_API_EXPORT OCCIStatementHandle
	{
		oc::Statement * m_stmt;
		OCCIEnvPtr m_env;

		OCCIStatementHandle(OCCIEnvPtr env);
		~OCCIStatementHandle();
		oc::Statement * createStatement(const std::string & sql);
		void CommitOnConnection();
		void RollbackOnConnection();
	};
	typedef boost::shared_ptr<OCCIStatementHandle> OCCIStmtPtr;

	class OCCIAccess;

	/**
	 * Retreiving data from a OCCI compatible database
	 */
	class GST_API_EXPORT OCCIDriver
		: public RDBDriverInterface
	{
		friend class OCCIAccess;

	public:

		//c'tors and d'tors
		OCCIDriver(HostPtr host, const std::string& dbname);
		virtual ~OCCIDriver();

		///@name RDB interface
		//@{
		virtual void connect();
		virtual void disconnect();
		virtual bool isConnected();
		virtual int getPID();
		//virtual TableAttributeDescListPtr ListTableAttributeDescs(const std::string& tableName);
		virtual void exec(const std::string & sqlStatement);
		virtual AbstractDataTablePtr exec_returning(const std::string & sqlStatement);
		virtual TableAttributeDescListPtr ListTableAttributeDescs(const std::string& tableName);
		virtual std::string ConcatenateStatements( const StatementBuilder & statements ) const;
		virtual std::string sqlesc(const std::string&) const;
		virtual std::string asUnquotedIdentifier(const std::string& identifier) const;
		//@}

		static std::string CreateOracleIdentifer(const std::vector<std::string> & tokens, const std::string & glue = std::string("_"));

		///occi callback
		static int FailoverCallback ( oc::Environment *env, oc::Connection *conn, void *ctx, oc::Connection::FailOverType foType, oc::Connection::FailOverEventType foEvent);

	protected:
		OCCIEnvPtr environment;
		static bool remember_ExtProcIsNotAvailable;

		void tryToWriteConsole(std::ostream & out);
		AbstractDataTablePtr resultToTable(oc::ResultSet * r, OCCIStmtPtr s);
		
		///@name OCCI using
		//@{
		OCCIStmtPtr createStatement(const std::string & sql);
		unsigned int executeUpdate(OCCIStmtPtr stmt, bool autoCommit = true);
		oc::Statement::Status execute(OCCIStmtPtr stmt, bool autoCommit = true);
		oc::ResultSet * executeQuery(OCCIStmtPtr stmt, bool autoCommit = true);
		oc::Connection * getConnection();
		std::string generateOCCIConnectionString() const;
		std::string getServiceName() const { return this->dbname; }
		static void WriteToClob(oc::Clob & clob, std::string & content, bool appendToMinSize = true);
		//@}
		
	};

} //of ns ClientUtils
} //of ns GST

#endif //_OCCI_DRIVER_H_